#include <unistd.h>
#include <string.h>
// #include <string>
#include <stdio.h>
#include <iostream>
#include <future>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <chrono>
#include <signal.h>

#define MAXLINE 8192
#define UDPPORT 8001
std::atomic_bool running(true);
int serverfd; // 套接字标识
using namespace std;

void signalHandle(int sig)
{
    if (sig == SIGINT)
    {
        std::cout << "关闭套接字体" << std::endl;
        running = false;
        close(serverfd);
        exit(1);
    }
}

int main()
{

    signal(SIGINT, signalHandle);

    unsigned int server_addr_length, client_addr_length;

    struct sockaddr_in serveraddr, clientaddr; // 存储套接字地址和端口的结构体

    // 使用函数socket()，生成套接字文件描述符；
    if ((serverfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) // 创建套接字，AF_INET:ipv4, SOCK_DGRAM: UDP
    {
        perror("socket() error");
        exit(1);
    }

    // 将地址与端口设置为0；
    bzero(&serveraddr, sizeof(serveraddr));
    // 设置服务器使用的协议，地址与端口
    serveraddr.sin_family = AF_INET; // 协议：ipv4
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(UDPPORT);

    server_addr_length = sizeof(serveraddr);
    // 使用bind()函数对套接字进行地址分配；
    // 服务器绑定端口号的原因是：避免系统自动分配导致的服务器启动的不可预测，以及显式的为客户端指明通讯节点
    if (bind(serverfd, (struct sockaddr *)&serveraddr, server_addr_length) < 0)
    {
        perror("bind() error");
        exit(1);
    }

    // 接收客户端的数据，使用recvfrom() 函数接收客户端的网络数据；
    client_addr_length = sizeof(sockaddr_in);
    int recv_length = 0;
    char recv_data[MAXLINE];
    auto thread_rec = std::async(std::launch::async, [&]
                                 {
                                     while (running)
                                     {
                                         std::cout << "等待客户端数据到达..." << std::endl;
                                         //等待客户端发送数据，并进行阻塞
                                         recv_length = recvfrom(serverfd, recv_data, sizeof(recv_data), 0, (struct sockaddr *)&clientaddr, &client_addr_length);
                                         if(recv_length != -1)
                                           std::cout  << recv_data << std::endl;
                                         sleep(1);
                                     } });
    // 向客户端发送数据，使用sendto() 函数向服务器主机发送数据；
    int send_length = 0;
    // char send_data[MAXLINE];
    std::string send_data = "hello client";
    // sprintf(send_data, "hello client !");
    auto thread_send = std::async(std::launch::async, [&]
                                  {
        int i = 0;
        while (running)
        {
             send_data = std::string("我是服务端, 这是我发的数据: ") + std::to_string(i++);
            // std::cout << "sizeof: " << sizeof(send_data) << " length: " << send_data.length() << std::endl;
           // std::cout << std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) << "  send: "  << send_data << std::endl;
           //传输数据
            send_length = sendto(serverfd, send_data.c_str(), send_data.length(), 0, (struct sockaddr *)&clientaddr, client_addr_length);
            std::cout << "\033[1;32m" << "我是服务端，已发出数据: " << send_data << "\033[m" << std::endl;
            //删除套接字中的目标地址信息
           // std::cout << "服务端发送数据" << std::endl;
            sleep(5);
        } });

    // 关闭套接字，使用close() 函数释放资源；
    //  close(serverfd);
    return 0;
}